﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using TTGame;
using System;

/*
 * Buff
 *
 * 挂载人物身上的持续效果。
 *
 * 要考虑的处理类型：
 * 临时的属性变化。
 * 永久的属性变化。如HP
 * 每秒的持续触发。
 * 光环，范围影响
 * 减免伤害，易伤
 * 控制BUFF
 *
 * Puppet需要处理逻辑分类
 *  -> 人物受到伤害时处理Buff
 *  -> 获取属性变化时处理Buff
 *  -> 实时更新。
 *
 * 以上有些是Puppet需要对Buff添加逻辑，如控制、属性变化。
 * 有些只是Buff自身的逻辑，如每秒触发，光环。
 *
 * Dot的次数：
 * buff触发之后立马触发一次。
 *
 *
 * 依赖：
 * Puppet
 *
 * ！不写重复代码！
 * @author TTun
 * @date 8/29/2017 4:25:26 PM
 */
namespace TTGameEngine {

public interface IBuff {
    bool Trigger(Puppet obj, string casterGID, int skillID, uint skillCastID);
    bool Fresh();
    void ClearBuff();
    bool UpdateBuff(float dt);
}

public abstract class Buff : IBuff {
    //Buff叠加层数。buff效果会根据层数不同发生改变。
    protected int m_curLayerCount;
    protected float t_remainingTime;
    public string m_casterGID;
    public Puppet m_reciver;
    protected bool m_isBuffRunning = false;
    public BaseBuffData m_buffBaseData;

    public static CountID_UInt buffGlobalID = new CountID_UInt();
    public uint m_buffGID; //全局Buff中唯一的ID
    public int BuffID;
    public GameObject m_effectObj;
    public int m_skillID;
    public uint m_skillCastID;

    public virtual void Init(BaseBuffData buffBaseData) {
        t_remainingTime = buffBaseData.m_duration;
        m_isBuffRunning = false;
        m_buffBaseData = buffBaseData;
        BuffID = buffBaseData.BuffID;
        m_buffGID = buffGlobalID.GetGID();
        m_buffBaseData.m_maxOverlayLayer = Mathf.Max(m_buffBaseData.m_maxOverlayLayer, 1);
    }

    public BuffType GetBuffType() {
        return m_buffBaseData.m_buffType;
    }

    /// <summary>
    ///Buff触发，添加到人物身上。
    /// </summary>
    /// <param name="reciver"></param>
    /// <param name="casterGID">为了防止施法者已死亡，尽量不直接引用puppet</param>
    /// <returns>true,需要持续运行。</returns>
    public virtual bool Trigger(Puppet reciver, string casterGID, int skillID, uint skillCastID) {

        m_isBuffRunning = true;
        m_reciver = reciver;
        m_casterGID = casterGID;
        m_skillID = skillID;
        m_skillCastID = skillCastID;
        onTriggerInstant();

        if(t_remainingTime <= 0) {
            BuffEnd();
        }

        AddEffect();
        DumpInfo();
        return m_isBuffRunning;
    }

    /// <summary>
    /// 重复上Buff，处理叠加buff
    /// </summary>
    /// <returns>false:已有重复Buff，根据设置，跳过未处理。</returns>
    public virtual bool Fresh() {
        //0:刷新  重新触发
        //1:不处理   跳过不处理。
        //>2:可叠加，叠加层数。   叠加逻辑由继承类处理
        int maxLayer = m_buffBaseData.m_maxOverlayLayer;
        if(maxLayer != 1) {
            Trigger(m_reciver, m_casterGID, m_skillID, m_skillCastID);
            return true;
        } else if(maxLayer == 0) {
            return false;
        }

        return true;
    }



    void AddEffect() {
        if(m_effectObj == null) {
            GameObject effectPrefab = GameObjectLoader.Ins.GetPrefabObj(GameConstant.PrefabPath_Effect + m_buffBaseData.effectPrefab) as GameObject;
            if(effectPrefab != null) {
                m_effectObj = ObjectRecycler.Instance.InstantiatePrefab(effectPrefab, Vector3.zero, Quaternion.identity);
                m_effectObj.transform.parent = m_reciver.GetPosTF(m_buffBaseData.effectPos);
                m_effectObj.transform.localPosition = Vector3.zero;
                m_effectObj.transform.localRotation = Quaternion.identity;
            }
        }
    }

    void RemoveEffect() {
        if(m_effectObj != null) {
            ObjectRecycler.Instance.Deactivate(m_effectObj);
            m_effectObj = null;
        }
    }

    /// <summary>
    ///用于处理每秒触发或者buff自身Time倒计时。
    /// </summary>
    /// <param name="dt"></param>
    /// <returns>false:buff结束了</returns>
    public virtual bool UpdateBuff(float dt) {
        if(false == m_isBuffRunning) { return false; }
        onUpdateBuff(dt);
        if(t_remainingTime <= 0) {
            BuffEnd();
        }
        t_remainingTime -= dt;
        return m_isBuffRunning;
    }

    public void ClearBuff() {
        BuffEnd();
    }

    public bool IsBuffRunning() {
        return m_isBuffRunning;
    }
    //Buff倒计时结束时
    protected virtual void BuffEnd() {
        m_isBuffRunning = false;
        t_remainingTime = 0;
        RemoveEffect();
    }

    //Buff即将结束
    protected virtual void onBuffEnd() { }
    //引用即时效果
    protected virtual void onTriggerInstant() {}
    //处理持续效果
    protected virtual void onUpdateBuff(float dt) {}

    /// <summary>
    /// 获取属性变化值。如果BUFF没有对属性有变化，那就返回0了。
    /// </summary>
    /// <param name="propID"></param>
    /// <param name="originValue">原始属性，用于百分比计算（根据配置）。如果属性是最大血量，那就是按最大血量百分比。如果是当前血量，那就是当前血量百分比</param>
    /// <returns></returns>
    public virtual float GetPropChangeValue(int propID, float originValue) {
        return 0f;
    }

    /// <summary>
    /// 应用Buff对受到的伤害的影响
    /// </summary>
    /// <param name="dmg"></param>
    /// <returns></returns>
    public virtual float ApplyReceiveDamage(float dmg) {
        return dmg;
    }
    /// <summary>
    /// 应用Buff对输出的伤害的影响
    /// </summary>
    /// <param name="dmg"></param>
    /// <returns></returns>
    public virtual float ApplyAttackDamage(float dmg) {
        return dmg;
    }

    string dumpInfoStr;
    public string GetDumpInfoStr() {
        if(string.IsNullOrEmpty(dumpInfoStr)) {
            dumpInfoStr = string.Format("[Buff] GID[{0}] ID[{1} {2}] obj[{3}]->[{4}] effect[{5}] Desc[{6}]",
                                        m_buffGID,
                                        m_buffBaseData.BuffID,
                                        m_buffBaseData.buffName,
                                        m_casterGID,
                                        m_reciver.GetGID(),
                                        m_buffBaseData.effectPrefab,
                                        m_buffBaseData.buffDesc);
        }
        return dumpInfoStr;
    }

    public void DumpInfo() {
#if UNITY_EDITOR
        DebugUtil.LogFormat("[Buff] {0}", GetDumpInfoStr());
#endif
    }

}

/// <summary>
/// 增减属性。
/// 尽量别用属性Buff来当做伤害去改变当前血量。属性改变血量是直接改属性值，不会有受伤动画、怒气、护盾等处理。
/// </summary>
public class PropBuff : Buff {
    public PropBuffData m_buffData;

    public override void Init(BaseBuffData buffData) {
        base.Init(buffData);
        m_buffData = buffData as PropBuffData;
    }

    protected override void onTriggerInstant() {
        //临时属性，等待Puppet获取属性时调用。即时修改属性，才需要立刻赋值。
        List<PropChange> propList = m_buffData.m_propsChange;
        for(int i = propList.Count - 1; i >= 0; i--) {
            if(propList[i].isEditProp == true) {
                applyPropChange(propList[i], m_reciver);
                propList.RemoveAt(i);
            }
        }
    }

    public override float GetPropChangeValue(int propID, float baseValue) {
        List<PropChange> propList = m_buffData.m_propsChange;
        for(int i = 0; i < propList.Count; i++) {
            if(propList[i].isEditProp == false && propList[i].propID == propID) {
                return propList[i].GetValueChange(baseValue);
            }
        }
        return 0f;
    }

    //直接应用PropChange
    void applyPropChange(PropChange propChange, Puppet receiver) {
        //改变obj的属性值
        int BuffPropID = propChange.propID;

        if(BuffPropID >= Puppet.BUFF_FLOAT_PROP_BEGIN) {
            //float属性
            PuppetFloatPropID propID = (PuppetFloatPropID)(propChange.propID - Puppet.BUFF_FLOAT_PROP_BEGIN);
            float objProp = receiver.m_prop.GetFloatProp(propID);
            float oldValue = objProp;
            objProp += propChange.GetValueChange(objProp);
            receiver.m_prop.SetFloatProp(propID, objProp);
            receiver.CallOnPropChange(propID, oldValue, objProp);
        } else {
            //int属性
            PuppetIntPropID propID = (PuppetIntPropID)propChange.propID;
            int objProp = receiver.GetRawProp(propID);
            int oldValue = objProp;
            objProp += (int)propChange.GetValueChange(objProp);
            receiver.m_prop.SetIntProp(propID, objProp);
            receiver.CallOnPropChange(propID, oldValue, objProp);
            if(propID == PuppetIntPropID.Prop_hp || propID == PuppetIntPropID.Prop_curHp) {
                //属性Buff的变化
//                 SynInfoUploader.Share().UploadHpChange(
//                     receiver.GetGID(),
//                     receiver.CurHp,
//                     receiver.MaxHp,
//                     0,
//                     (int)DamageSource.Buff,
//                     BuffID,
//                     m_casterGID,
//                     t_remainingTime);
            }
        }
    }
}

public class HPBuff : Buff {
    public HPBuffData m_buffData;
    public int t_lastCount;
    public float t_intervalTime;
    public float t_buffCDTime;

    public float t_valuePreDot;

    public override void Init(BaseBuffData buffData) {
        base.Init(buffData);
        m_buffData = buffData as HPBuffData;
    }

    public override bool Trigger(Puppet reciver, string casterGID, int skillID, uint skillCastID) {
        bool result = base.Trigger(reciver, casterGID, skillID, skillCastID);

        var dr = DamageRecount.Share().GetDRinfo(skillCastID);
        if(dr != null) {
            float dmgValue = m_buffData.m_hpChange.GetValueChange(m_reciver.GetRawProp(PuppetIntPropID.Prop_hp));
            float dotValue = m_buffData.m_hpChangeDot.GetValueChange(m_reciver.GetRawProp(PuppetIntPropID.Prop_hp));
            if(dmgValue > 0) {
                dr.AddHealth(dmgValue);
            } else {
                dr.AddDamage(dmgValue);
            };
            if(dotValue > 0) {
                dr.AddHealth(dotValue);
            } else {
                dr.AddDamage(dotValue);
            };
        }

        return result;
    }


    protected override void onUpdateBuff(float dt) {
        if(t_lastCount > 0) {
            if(t_buffCDTime <= 0) {
                //触发一次
                triggerDot();
                t_buffCDTime = t_intervalTime;
                t_lastCount--;
            }
            t_buffCDTime -= dt;
        }
    }

    public override bool Fresh() {
        if(base.Fresh() == false) {
            return false;
        }
//         //处理叠加逻辑
//         Trigger(m_reciver, m_casterGID);
//         //刷新持续时间
//         t_remainingTime = m_buffData.m_duration;
//         //层数增加
//         m_curLayerCount = Mathf.Min(m_curLayerCount + 1, m_buffData.m_maxOverlayLayer);

        return true;
    }

    void prepareValue() {
        t_lastCount = m_buffData.m_hpChangeDot.changeCount;
        t_intervalTime = m_buffData.m_duration / t_lastCount;
        t_buffCDTime = 0;
        t_valuePreDot = m_buffData.m_hpChangeDot.GetValueChange(m_reciver.GetRawProp(PuppetIntPropID.Prop_hp)) / t_lastCount;
    }

    protected override void onTriggerInstant() {
        prepareValue();
        if(m_buffData.m_hpChange.IsAvailable()) {
            float changeValue = (int)m_buffData.m_hpChange.GetValueChange(m_reciver.GetRawProp(PuppetIntPropID.Prop_hp));
            applyDamage(changeValue , changeValue > 0 ? DamageType.Healing : DamageType.Damage);
        }
    }

    protected override void onBuffEnd() {
        if(t_lastCount > 0) {
            triggerDot();
        }
    }

    void triggerDot() {
        if(m_buffData.m_hpChangeDot.IsAvailable()) {
            applyDamage(t_valuePreDot, t_valuePreDot > 0 ? DamageType.Healing : DamageType.Damage);
        }
    }

    void applyDamage(float dmg, DamageType dmgType) {
        dmg = Math.Abs(dmg);
        DamageInfo info = DamageInfo.CreateDamageInfoWithRealDamage(m_casterGID, m_reciver.GetGID(), (int)dmg, m_skillID, m_skillCastID, BuffID, t_remainingTime, DamageSource.Buff, dmgType);
        m_reciver.ApplyDamage(info);
    }


}

/// <summary>
/// 护盾
/// 有着防护数值的BUFF。
///
/// 层数，是指buff的层数，每层护盾减为0后，减一层。
/// 重复释放，不可叠加。
///
///
/// 1、固定数值
/// 2、最大血量百分比
/// 3、护盾层数/次数
///
/// 逻辑处理：
/// 人物计算伤害时，考虑护盾
///
///
/// </summary>
public class ShieldBuff : Buff {
    public ShieldBuffData m_buffData;
    float m_shieldLayerValue;       //每层护盾值
    float t_curShiledLayerValue;    //当前护盾值
    float t_shieldRemainTotalValue; //总护盾剩余值
    public override void Init(BaseBuffData buffData) {
        base.Init(buffData);
        m_buffData = buffData as ShieldBuffData;
    }

    protected override void onTriggerInstant() {
        //准备数据
        m_shieldLayerValue = m_buffData.valueChange;
        if(m_buffData.precentChange != 0) {
            m_shieldLayerValue += m_buffData.precentChange * m_reciver.GetPropWithBuff(PuppetIntPropID.Prop_hp);
        }
        m_curLayerCount = Mathf.Max(m_buffData.shieldInitLayer, 1);

        t_curShiledLayerValue = m_shieldLayerValue;
        t_shieldRemainTotalValue = m_curLayerCount * m_shieldLayerValue;
    }

    /// <summary>
    /// 护盾受到攻击，返回没有被抵消的伤害。
    ///
    /// </summary>
    /// <param name="dmg"></param>
    /// <returns></returns>
    public override float ApplyReceiveDamage(float dmg) {
        if(m_shieldLayerValue < 0) {
            return dmg;
        }
        float dmgResult = 0;
        if(m_buffData.isOverHurt) {
            //盾破后伤害继续计算。
            t_shieldRemainTotalValue -= dmg;
            if(t_shieldRemainTotalValue <= 0) {
                dmgResult = -t_shieldRemainTotalValue;
                BuffEnd();
            }
//             else {
//                 m_curLayerCount = (int)Mathf.Ceil(t_shieldRemainTotalValue / m_shieldLayerValue);
//                 t_curShiledLayerValue = t_shieldRemainTotalValue % m_shieldLayerValue;
//             }

        } else {
            //盾破后，不受伤害
            t_curShiledLayerValue -= dmg;
            if(t_curShiledLayerValue < 0) {
                m_curLayerCount--;
                if(m_curLayerCount <= 0) {
                    BuffEnd();
                } else {
                    t_curShiledLayerValue = m_shieldLayerValue;
                }
            }
        }

        return dmgResult;
    }
}

public class DamageIncBuff : Buff {
    public AttackDamageBuffData m_buffData;
    public override void Init(BaseBuffData buffData) {
        base.Init(buffData);
        m_buffData = buffData as AttackDamageBuffData;
        //mark:todo create Buffs from datas
    }

    protected override void onTriggerInstant() {
    }

    //处理持续效果
    public override float ApplyAttackDamage(float dmg) {
        float dmgResult = dmg;
        dmgResult += m_buffData.m_dmgChange.valueChange;
        if(dmgResult > 0) {
            dmgResult += (dmg * m_buffData.m_dmgChange.precentChange);
        }
        if(dmgResult < 0) {
            dmgResult = 0;
        }

        return dmgResult;
    }

}

public class DamagePreventBuff : Buff {
    public ReciveDamageBuffData m_buffData;
    public override void Init(BaseBuffData buffData) {
        base.Init(buffData);
        m_buffData = buffData as ReciveDamageBuffData;
        //mark:todo create Buffs from datas
    }

    /// <summary>
    /// 减免受到的伤害。
    ///
    /// </summary>
    /// <param name="dmg"></param>
    /// <returns></returns>
    public override float ApplyReceiveDamage(float dmg) {
        float dmgResult = dmg;
        dmgResult -= m_buffData.m_dmgChange.valueChange;
        if(dmgResult > 0) {
            dmgResult += (dmg * m_buffData.m_dmgChange.precentChange);
        }
        if(dmgResult < 0) {
            dmgResult = 0;
        }

        return dmgResult;
    }
}

public class StateBuff : Buff {
    public StateBuffData m_buffData;
    ControlInfo m_controlInfo;

    public override void Init(BaseBuffData buffData) {
        base.Init(buffData);
        m_buffData = buffData as StateBuffData;
        if(m_controlInfo == null) {
            m_controlInfo = new ControlInfo();
        }
        m_controlInfo.m_controlAnim = m_buffData.m_controlAnim;
        m_controlInfo.m_controlState = m_buffData.m_controlState;
        m_controlInfo.m_controlTime = m_buffData.m_duration;
        //m_controlInfo.m_isSynAnim = false;
    }

    protected override void onTriggerInstant() {
        m_reciver.ApplyControlState(m_controlInfo);
    }
}


}
